Win32 Global API Hook - 2 ٸ μ ּҰ !! (2)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

 ٵ ߼޴  ̴... ٻ ־  ʰ ¸ øԵǾϴ. ʱ
 ֽñ... (ƹ ٸ ̴ٸ ... ...-.-;;) , ʰ ¸ŭ  ؾ
?  ð ̾ ٸ μ ּҰ ѳ ִ  ؼ ˾ƺ 
. ð ȵ   NUMEGA SOFTWARE ý Ͼ Matt Pietrek ̵
 ° Advanced Windows  Jeffrey Ritcher Debugging Applications  John 
Robbinson  ο߾,   α׷  ý ŷĮ ٷ  ־ 
Դϴ. API ŷ  ʸ ٷ ̱⵵ . ׷ ³ϴ.
 
(  Ī մϴ.)

  ׷ 츮 Ϸ ߴ غ. ̹   ٸ μ ּҰ 츮 
غڴ ̾.  ϸ ٸ μ ּҰ   ? ƴ װͺ 
 μ ּҰ ѳ    غ.    ǥΰ 
 ϰ̴.  Visual C++    ϴ° ѹ غ. ſ 
  α׷  ٸ μ̴. ġ Ŵ   α׷(, 
 ϴ μ Ѵ.)   ϰų   ִ. Ŵ Ϸ Ҿ 
α׷    ɰ, ٵ ƽôٽ ε Ÿ ϴ° 
Ϸŭ̳ ϰ  ۾̴. ... ڴ  ۵  Ϸ Ű 
 ٴ°  ƽ( ̶ C  ѱ۾ ־ , DOS̾
 ȴ.)  츮 ڵ ɷ ļ⺸ٴ ϴ ϴµ ʿ ð 
¿      ̶ ϰ̴. ... ¶ Ⱑ  õ
 µ, ٽ  ⸦ غ. ¶ Ŵ Ȯ ٸ μ ּҰ ѳ 
ȴٴ° ǽ  ° .
 
 ׷ٸ?, 츮 ׿  ۾    ? Win32 API ٸ μ ּҰ 
Ҽ ִ APIƮ Ѵ. ̰ ٷ Debugging API ̴. Ƹ ó    
. 鹮 ҿϰ,   MSDN  "WriteProcessMemory" Ÿغ. ׷ 
WriteProcessMemoryԼ   ǥõɰ̴. (WriteProcessMemory ǥ  API ̸
״ μ ޸𸮸 (WRITE)ϴ Լ̴.) Win32 μ ּҰ ö ȣ
ȴٴϸ ׷ ʳ? ̰ ʹ ̰ݾ?  ̷ ϴ е鵵  𸣰ڴ. ׷ 
ü  ׸ ϰ ۵Ǿڴ°? Debugging API ״ Debugging ؼ, Ǵ 
 ϱ   ̹ܳǷ 츮    Ϸµ   
 ִ.  ϸ   API Ҽ ִ  ſ ̶ ̴. Ƿʷ 
WriteProcessMemory ٸ μ ּҰ Ϸ μ  Ű 
 ſ ٷο  ľ ϸ, ׳ ü  ζ ϴ. (ü, 
Ȯ ϸ  ý API Win9x  ʰų,  ȴٴ ̴.)
 
  ϸ ݱ   Win9x Ѵ. WinNT/2000   
  .    WinNT/2000 ڰ Ѵ  ʾ̴. NT迭
(2000, XP) ü 9x迭 ü ⿡ غ̰ κ ø̼ ȣȯ
µ ,    ϰ ִ.  ϸ API ŷ  ̵ 9x
 NT迭̳  ٸ  ϴ  ־ ̸ . ߶ϸ 9x NT迭 
.  9x ȣȯ  DOS Windows 3.x α κ ϰ ֱ⶧̴. ᱹ 
ȣȯ ü  ո  Ҽۿ  ε, 9x NT迭 Ҿ
  ⿡ ִ. ϴ ü  ü  ߿ ̹̽ ¿ ڼ 
˾ƺϰ 츰 9x ۾Ѵٰ ϰ ¸ ϵ .
 
 츮 ٸ μ ּҰ ۾  ִ  ȿ   ? 翬 DLL
 ̿ϴ ̴. ٵ ƽôٽ DLL DLL ε μ ּҰ εǸ 󸶵 
 ڿ   ִ. ׷ 츮 ϴ ۾ ϴ DLL Ѵ, ׳༮ 
 μ ԽŰ ɰ̴.
 
 ׷,   α׷ ƴѳ༮   ϴ DLL Ҽ ?  ¿
 ü α׷  Ű   ִ. ᱹ Ϸ ̳ʸ 
, CPU  Ͽ  ڵ带 ã  سٰ ߴ. ׷ٸ 츮  
ڵ带 ϴ ڵ ٸ? 翬   ڵ尡  ̴.  
°  ֱġ( . ^^ ޸𸮸 ϴ°̴.) εĿ ȴٰ 
. ׷ٸ  ε  ã   Debugging API ϴ ڵ念  
 ڵ ٲġ, Ű ɰ̴. , ̵ ſ ϴ. ׷    
   .
 
1. μ ڵ带 ˾Ƴ.
 : Debugging API ؼ Ưμ ڵġ ˾Ƴ  ִ.  Ѵ 츮 9x
 츮 μ ߽Ű 쿡 ϵ.
 
2. ϴ ڵ带 Ѵ.
 : Ƹ  ø̼ α׷(κ VC++, VB, Delphi  ۾ ̴.) ϱ 
ϴ κϰ̴. ֳĸ , Ȯ ϸ ڵ带 ۼؾ ϱ⶧̴.  
 α׷ϴ     ƴ α׷ӿ ׷  α׷
 и ̰ ִ. ݵ  ̿ؼ α׷ ʴ  ˸  
ýۿ  ذ и̴. ̹ ¿ ſ   ڵ常 , ڽ
 α׷ õ ˰ ִٸ( ¸  κ  ׷̶ ڴ ϰ 
.) ݵ  ϱ ٶ. ( ؼ   "Win32  α׷" 
ٽ ٷ絵 .)
 
3. ڵ带 .
 : ϴ  ϴ ڵ带  ڵ忡 .
 
4. ʿ  Ǿٸ ڵ带 Ѵ.
 : 3  ڵ带 / Ѵ.
 
ü ۾ 帧 ̷. , ׷  Ӹ ,  ڵ带 غ .

׷   Ÿ  Win32 α׷ Ѵ. ϴ ׳  Ǵ Ʈе
 ׳  ᵵ   ߿ API ŷ ׽ƮϷ ϳ δ°͵ ̴. 
ϰ VC++ Win32 Application - Hello World α׷ ؼ AppWizard   
. غ ׳ ޶  ߰, Ŭ̾Ʈ  "Hello, World" µɰ̴.

  μ   DLL ϳ Ѵ. ϴ ٸ μ  εǾ° Ȯ
ϱ , Ʒ  μ   ޽ ڽ ִ  DLL 
.

BOOL APIENTRY DllMain(HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved)
{
    switch(ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        MessageBox(NULL, "DLL_PROCESS_ATTACH", "TestDll", MB_OK);
        break;
    case DLL_PROCESS_DETACH:
        MessageBox(NULL, "DLL_PROCESS_DETACH", "TestDll", MB_OK);
        break;
    }

    return TRUE;
}

ϴ    ̴. ׷ μ DLL ϴ  غ.
ռ μ  Ѿ Ѵٰ ߴ. Ʒ  μ   
.

CreateProcess(NULL, 
    (LPSTR)szCmdLine, 
    0, 
    0, 
    FALSE,
    DEBUG_ONLY_THIS_PROCESS, 
    0, 
    0, 
    &StartupInfo, 
    &ProcessInfo);

 CreateProcess 6° ڷ DEBUG_ONLY_THIS_PROCESS ذͿܿ Ư  . ׷ 
szCmdLine  μ  μ ( ߴ.  ϴ μ 
̴.) ȴ. ׷  (ٷ  μ ȴ.)  ̺Ʈ ߻Ų. 
  ̺Ʈ ڵ鸵ν ϴ ۾   ̴. Ʒ ڵ带 .

DEBUG_EVENT event;
DWORD dwContinueStatus;

while(1)
{
    //  ̺Ʈ ߻Ҷ 
    WaitForDebugEvent(&event, INFINITE);

    dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;

    if(CREATE_PROCESS_DEBUG_EVENT == event.dwDebugEventCode)
    {
        //  μ  ̺Ʈ
        TRACE("CREATE_PROCESS_DEBUG_EVENT fired !!\n");

        //  μ 
        m_ProcessDebugInfo = event.u.CreateProcessInfo;
    }
    else if(EXCEPTION_DEBUG_EVENT == event.dwDebugEventCode)
    {
        //   ̺Ʈ
        TRACE("EXCEPTION_DEBUG_EVENT fired !!\n");
        HandleException(&event, &dwContinueStatus);
    }
    else if(EXIT_PROCESS_DEBUG_EVENT == event.dwDebugEventCode)
    {
        //  μ  ̺Ʈ
        TRACE("EXIT_PROCESS_DEBUG_EVENT fired !!\n");
        return;
    }

    //  μ  ѱ.
    ContinueDebugEvent(event.dwProcessId, event.dwThreadId, dwContinueStatus);
}

 EXIT_PROCESS_DEBUG_EVENT ̺Ʈ ö ѷ ϴ  ˼ ִ. 
EXIT_PROCESS_DEBUG_EVENT ̺Ʈ  μ(== ) ɶ ߻Ѵ. 츮 óؾ 
 ̺Ʈ ̰Ϳܿ CREATE_PROCESS_DEBUG_EVENT  EXCEPTION_DEBUG_EVENT ̺Ʈε ̸ ״ 
Ⱑ ɶ ⿡ ܰ ߻Ҷ ſ ߻Ѵ. 츮 ⼭ μ  
, ڵ带  Ѵ.  츮     ٷ EXCEPTION_DEBUG_EVENT ̺Ʈ
ε, ̳༮ Ʊ Ѵ Ⱑ ܸ ų ŷ ߻Ǵ ̺Ʈε,   
  ˴ٽ  ÷ο, 0 , ٱ  ִµ,   Ҷ ϴ 
ߴ(극ũƮ)    ̴. ߴ Ⱑ Ǵ 
(CREATE_PROCESS_DEBUG_EVENT )  δ ؼ ѹ ߻ϸ, 翬 ߴ 
 쿡 ߻Ѵ. ׷ HandleException() Լ  .

// 극ũ Ʈΰ?
if(EXCEPTION_BREAKPOINT 
    == pEvent->u.Exception.ExceptionRecord.ExceptionCode)
{
    TRACE("EXCEPTION_BREAKPOINT fired !!\n");

    if(0 == m_uBreakCount)
    {
        // ù° 극ũ Ʈ
        TRACE("First EXCEPTION_DEBUG_EVENT fired !! - InjectSpyDll() Call !!\n");
        if(!InjectSpyDll())
            TRACE("ERROR : InjectSpyDll() Fail !!\n");
    }
    else if(1 == m_uBreakCount)
    {
        // ι° 극ũ Ʈ
        TRACE("Second EXCEPTION_DEBUG_EVENT fired !! - ReplaceOriginalPagesAndContext() 
Call !!\n");
        if(!ReplaceOriginalPagesAndContext())
            TRACE("ERROR : ReplaceOriginalPagesAndContext() Fail !!\n");
    }

    m_uBreakCount++;
    *pContinueStatus = DBG_CONTINUE;
}
else
    *pContinueStatus = DBG_EXCEPTION_NOT_HANDLED;

 ù° ߴ Ⱑ  Ŀ ѹ ߻Ѵٰ ߴ.  츮 ڵ带   
ٷ ̺κ Ǿ Ұ̴.   Ǳ ̸, 츮  ù ڵ忡 츮
 ڵ带  ̴. ι° ߴ ڵ带 ϱ ؼ,  ڵ忡 ִ
, ŷ  ѱ  ȴ. ̺κп ڵ带 ־  ̴.

 ׷  ڵ带  κ(InjectSpyDll()) 캸. 
 
// LoadLibraryA() ּ
FARPROC pfnLoadLibrary = GetProcAddress(
    GetModuleHandle("KERNEL32.DLL"), "LoadLibraryA");

//  μ ù°  
m_pFirstCodePage = FindFirstCodePage(m_ProcessDebugInfo.hProcess, 
    m_ProcessDebugInfo.lpBaseOfImage);

//   ؽƮ 
m_OrgContext.ContextFlags = CONTEXT_CONTROL;
GetThreadContext(m_ProcessDebugInfo.hThread, &m_OrgContext);

BOOL    bRetCode;
DWORD    cBytesMoved;

//  μ ù°  
bRetCode = ReadProcessMemory(m_ProcessDebugInfo.hProcess, m_pFirstCodePage, 
    m_pOrgCodePage, sizeof(m_pOrgCodePage), &cBytesMoved);
if(!bRetCode || sizeof(m_pOrgCodePage) != cBytesMoved)
    return FALSE;

//  DLL  ε ƾ  ü 
PFAKE_LOADLIBRARY_CODE pNewCode = (PFAKE_LOADLIBRARY_CODE)m_pFakeCodePage;

// sub esp, 1000h
pNewCode->instr_SUB = 0xEC81;
pNewCode->operand_SUB_value = PAGE_SIZE; // ũ(4096);

// push <Ű>
pNewCode->instr_PUSH = 0x68;
pNewCode->operand_PUSH_value = (DWORD)m_pFirstCodePage 
    + offsetof(FAKE_LOADLIBRARY_CODE, data_DllName);

// call <Լּ> ; LoadLibraryA() ȣ
pNewCode->instr_CALL = 0xE8;
pNewCode->operand_CALL_offset = (DWORD)pfnLoadLibrary 
    - (DWORD)m_pFirstCodePage - offsetof(FAKE_LOADLIBRARY_CODE, instr_CALL) - 5;

//  극ũ Ʈ 
pNewCode->instr_INT_3 = 0xCC;

// Ű (ε  DLL)
char pszDll[MAX_PATH];
if(!GetSpyDllName(pszDll, sizeof(pszDll)))
    return FALSE;
strcpy(pNewCode->data_DllName, pszDll);

// 츮 ƾ μ Write !!
bRetCode = WriteProcessMemory(m_ProcessDebugInfo.hProcess, m_pFirstCodePage, 
    &m_pFakeCodePage, sizeof(m_pFakeCodePage), &cBytesMoved);
if(!bRetCode || sizeof(m_pFakeCodePage) != cBytesMoved)
    return FALSE;

//  Ʈ(EIP) ù°  
m_FakeContext = m_OrgContext;
m_FakeContext.Eip = (DWORD)m_pFirstCodePage;

//   ؽƮ 
if(!SetThreadContext(m_ProcessDebugInfo.hThread, &m_FakeContext))
    return FALSE;

return TRUE;

 ڵ尡  䵥, 帧 ̷.  츮 ϱ⸦ ϴ ڵ ̷. ٷ 츮 ռ  
testdll.dll  Ͽ εϰ ϴ°̴. Cڵ ϸ ⿡ Ʒ  ڵ带 
 ̴.

LoadLibrary("testdll.dll");

׷ ̷ ۾  ڵ带 غ. к ϸ  Ʒ  ڵ尡 ɰ̴.

push <"test.dll" ּ>
call <LoadLibrary Լּ>
int 3

 C Ķ͸ нϴ   ̿ϴ ̴. Լ Ķ н ͸ ̿
   ̿ϴ  ִµ, Ϲ  C Ķʹ  ؼ Ѱ.
(ԼȣԾ࿡ ؼ   "Win32  α׷" ڼ ٷ絵 .) ¶  
 ڵ带 ؼ 츮 ϴ DLL εɰ̸, ۾  ڵ   ŷ 
 Ѱܾ ϴµ, ̸  ߴ Ѵ. ߴ  ڵ ͷƮ 3 , int 3 
.

 ׷  ڵ带  ȯѺ. ׷  ִ. test.dll̳ LoadLibrary Լ
ּҸ  óؾ ϴ°ϱ?  LoadLibrary ԼּҸ ãƺ. GetModuleHandle(), 
GetProcAddress() Լ ּҸ ˾Ƴ   ̴. ( 9x) ׷  Լּ
  CPU ؼҶ  ϴ ˾ƾҰ̴. call ̳ jmp   
 ϴ ɾ 32Ʈ ȯ濡  5Ʈ ũ⸦ µ, ̴ ɾڵ 1Ʈ
 ̵ ּ 4Ʈ(32Ʈ 巹̹Ƿ) ̷. ׷ ɾ ĶͰ Ǵ ּҴ 
ּҰ ƴϰ ̴ּ. ׷ϱ  call  ϰ ƿ ּҸ  ̵ 
ҿ   ڵ带 Ѵ.   call 100 ̶   ġ ּҰ 50
    ȯǸ 0xe8(call ɾ) 100(̵ּ) - 50(  ּ) - 5(
  ũ) ȴٴ ̴.  0xe845000000 ڵ尪 ȯ ̴.( Ϲ
   ּҰ Win32 ȿҼ .) ׷ٸ  LoadLibararyA ԼּҰ 
0xbff77750
̰,   ڵ ּҰ 0x00401bc2  Ѵٸ LoadLibraryA ȣϴ  ڵ 
  ̴. 0xe8895bb7bf(call bff77750h) (Intel 迭 CPU  Ѵٴ°
 . 0x12345678  ޸𸮻󿡴 0x78, 0x56, 0x34, 0x12 ȴ.)

 , Լȣ  ̷ ˾  Ķ͸  ϴ° ˾ƺ. κ
 ߵ C Ϲ  ؼ Ķ͸ Ѵٰ ߴ. ÿ Ķ
("testdll.dll") Ǫϰ   Լ ȣָ ǰڴµ, 츮  Ķʹ 
 ڰ ܼ ƴϰ ̴. ׷ٸ  ڿ  ִ ͸ 츮 
־ ϸ װ  ãƼ α׷ ϴ  츮 ־ Ұ̴. 
   ð    Ҵָ, ڵ峻 ̵ ãƼ ɼ 
 Ѵ. ׷Ƿ α׷Ӵ ͸  ؾ ϴ Ű澵 ʿ䰡 Եǰ, ܼ
  ̸θ ϸ ȴ. 츮  ڵ   ϰ  డ ڵ
 ̷ ۾  Ϸ . ׷Ƿ ͸ ϴ  츮  
־ Ұ̴. ϴ 츮  ɼ ־ ϹǷ  ϴ  
⿡  ִ. ᱹ  ̿ؾ ϴµ Ϸ  ÿ Ѵ. (¿
 ٽ ٷ ϴ ͸ ҽѼ    ҴѴٰ ˾Ƶ. ̺κ
  Ҷ  ߿ ̹Ƿ  ˾Ƶε .) ͸ ҽŰ  
 ڿ  ͸ ְ  ڿ ּҸ ٽ ÿ ǪѴ LoadLibraryA ȣѴ
 ϴ DLL ε  ̴.

 ü ڵ(ڵ   н 迭 ü Ʈ ѿ Ǵ α׷ 
ڵ带 ؼ Ʈ   ȹҼ ְ ϴ ŷ ڵ嵢 Ѵ. ֱٱ ߴ 
ÿ÷ο ŷ  ˷,  ּҸ   ڵ带 Ѵ.)
 Ǿٸ   ̷   ڵ带  ڷᱸ Ʒ  غѴ.
 
// ü 1Ʈ packingѴ.
#pragma pack(1)

// μ ֻ ƾ(LoadLibraryA())
typedef struct _FAKE_LOADLIBRARY_CODE{
    WORD    instr_SUB;
    DWORD    operand_SUB_value;
    BYTE    instr_PUSH;
    DWORD    operand_PUSH_value;
    BYTE    instr_CALL;
    DWORD    operand_CALL_offset;
    BYTE    instr_INT_3;
    char    data_DllName[1];
}FAKE_LOADLIBRARY_CODE, *PFAKE_LOADLIBRARY_CODE;

 ϴ 1Ʈ ü ϵ , ü  ʵ带 äִ   Ʈ ڵ
 ϱ ٶ,  츮  ü   Ʒó ɰ̴.

sub esp, 1000h
push <"test.dll" ּ>
call <LoadLibrary Լּ>
int 3

 ó ͸ 0x1000(4096)ŭ ҽŲ Ʊ ߵ ġ Ϸ   
 Ȯϵ 츮 ͸  ð ȮѰ̴.
 
 !! ¶ ڵ尡 ϼǾٸ ̳༮ μ ڵ念  Ű⸸ ϸ 츮 
ϴ ۾(LoadLibraryA("testdll.dll")) ̴ٰ. ׷ٸ  ΰ? 츮 
α׷  óڵ忡 츮 ڵ带 ν  츮 ϴ ۾ , ڵ带 
ؼ ġ μ ƹϾٴµ ǰ  ̴. ׷ٸ  μ ڵ 
ùκ ãƳ ϴµ, ̸ ؼ FindFirstCodePage() Լ  .
 
BOOL    bRetCode;
DWORD    cBytesMoved;
DWORD    peHdrOffset, baseOfCode;

//  μ ù°  .
bRetCode = ReadProcessMemory(hProcess, (PBYTE)pProcessBase + offsetof(IMAGE_DOS_HEADER, e_lfanew),
    &peHdrOffset, sizeof(peHdrOffset), &cBytesMoved);
if(!bRetCode || sizeof(peHdrOffset) != cBytesMoved)
    return FALSE;

bRetCode = ReadProcessMemory(hProcess, (PBYTE)pProcessBase + peHdrOffset
    + 4 + IMAGE_SIZEOF_FILE_HEADER
    + offsetof(IMAGE_OPTIONAL_HEADER, BaseOfCode),
    &baseOfCode, sizeof(baseOfCode), &cBytesMoved);
if(!bRetCode || sizeof(baseOfCode) != cBytesMoved)
    return FALSE;

return (LPVOID)((DWORD)pProcessBase + baseOfCode);

 ״ ٷο ° . 1 ߴ PE ߴٸ     
̴. μ ̽巹 ڵ ̽ 巹ŭ    ȯش. 
 ġë ڵ ̽ 巹  ּҶ    ̴.
 
 ¶    ؽƮ ù° ڵ , Ʊ  ڵ带 
 ù° ڵ . ״   ؽƮ ͸  ù° ڵ
 Ѵ.  ؽƮ     Ƽ ¤ Ѿ  ؽƮ
 Ʊ״   ¸ ϰ ִ. κ CPU Ϳ  ε  츮
  ˰ Ѿ eip(Ȯ νƮ )̴.  Ͱ  ִ ʹ  
 ڵּҸ  ִ.   ༮ ϰ Ǹ α׷ 帧 ϴ  
 ִ. VC++ ſ ϴ Set Next Statment  ٷ  eip ϹǷν 帧 
ϴ   Ǵ ϽŲ. ϰڴٸ VC++ ſ  츦 ѵ eip  
غ. α׷  eip  ּҷ ϴ   ̴.(帧 
° ýα׷ 뿡  Ѱ ø̼  뿡  
 ʴµ ϴ. Set Next Statment  VC++ ſ ſ  ̹Ƿ  صε . 
׷ ϰ Ǹ  ų ų  Ȳ ʷϱ⵵ ϹǷ  ˰ ؾ Ұ
̴.)

  ReplaceOriginalPagesAndContext() Լ  ڵ ؽƮ  
 Լ̴. 
 
BOOL    bRetCode;
DWORD    cBytesMoved;

// ù°   ؽƮ  ǵ.
bRetCode = WriteProcessMemory(m_ProcessDebugInfo.hProcess, m_pFirstCodePage, 
    m_pOrgCodePage, sizeof(m_pOrgCodePage), &cBytesMoved);
if(!bRetCode || sizeof(m_pOrgCodePage) != cBytesMoved)
    return FALSE;

if(!SetThreadContext(m_ProcessDebugInfo.hThread, &m_OrgContext))
    return FALSE;

return TRUE;

  InjectSpyDll()  ξ  ؽƮ ܼ ǵν μ() 
ڽ  ߴ ä  ȴ.
 
< !!>

 ð´ ణ  з ¿ . 츮  ٸ μ 츮   
ϴ  .  ѺпԴ  ſ ¿̴. ̹ ´  
α׷ ҽڵ带  ø ϰڴ.  ø ҽڵ带 мغ ˰  
 κ   ܵǾ ׸  ʰų  ߿  κ̴  ȥ 
Ҽ Ŷ ϴ´.
 
  1  μ DLL  , װ ٸ μ ؼ  ٸ μ
 API ŷ ַ , ó     ٶ ٷ ߴ. ̺κ
 е   غٶ. 1 ٷ   μ ּҰ ȿ 
API ŷ̾Ƿ ̰ DLL    μ ԽŰ  μ API 
ŷҼ ̴.
 
 ׷  µ  쿡   ִ APIŷ̶ ϱ⿡ ڶ . ϴ Ʈ
̺ ϴ  Ѱ谡 ִٴ  ְ ʹ.   쿡    
 ʴ 쵵 ִٴ° ϱ ٶ. ׹ۿ Ƽ   , Ϲȭϱ ؼ
 Ѿ   . ׷    API ŷ  ʰ Ǿ ӿ Ʋ
. ð  ϰų Ǵ ߸  ְ   븸ŭ  
ֱ ٶ.
 
  ´ Win32  α׷ֿ ؼ  2ȸ ļ ¸  ̴. 

<⼳...>

  ι° ¸ Ʊ. ó Ҷ   ˾Ҵµ  𰡸  
ٴ   ƴϱ.  ó ¸   ̰  ׵ ߴ 
 Ϸ  ǽϴٸ, åְ Ѵٴ°   δ Ȱִ±. ׵  
   ð ߰ ħ ɼ ߰ ۵ ⻵߽ϴ.   ׷
  µ    Ǿ մϴ.  ° йٴ й 
 αⰡ , ݱٴ ֽ࿡  ̸ ٴϴµ 츮 ڵ  
Ÿ  .  α׷Ӱ VC++ ȯ RAD  ͼְ, VC++ 
 Ŀ  Ŀǵο ϴ ܼ־ø̶̼  𸣰 ִ ڰ 
 ǿ ¼ ô븦 Ųٷ µ  鶧  ֽϴٸ ýα׷ и 
п ο  ٰԴϴ.  ȯ ϳ ڴٸ make ƿƼ ̿ 
Ʈ, ġ  ϰ ũ, 츮  α׷ ζ Ͼ͵  
ô  ذ ۱ ,     ,   ڴ
 ۾   ־ Ѵٴ° ̳ ̳ ԾԴϴ. ⼳ . 
׷  ¿ ٽ ˱ ٶ,  оּż մϴ.
 
P.S :  ´ 󸶵 ٸ Ʈ Ǿ  ,  뵵 Ǿ , 
 Ǹ  մϴ. 縦 ϽǶ ǻ  ̸ ֽñ ٶϴ.